package com.huilian.iotbox.admin.wap.service.impl;

import com.alibaba.fastjson.JSON;
import com.huilian.iotbox.admin.wap.dao.PermissionDao;
import com.huilian.iotbox.admin.wap.service.PermissionService;
import com.huilian.iotbox.admin.wap.service.RolePermissionTempService;
import com.huilian.iotbox.admin.wap.service.RoleService;
import com.huilian.iotbox.admin.wap.service.UserPermissionService;
import com.huilian.iotbox.data.common.RedisKey;
import com.huilian.iotbox.data.common.ServerResponse;
import com.huilian.iotbox.data.dto.RolePermissionTempDto;
import com.huilian.iotbox.data.enums.PermissionOpenSettingEnum;
import com.huilian.iotbox.data.enums.PermissionPlatformTypeEnum;
import com.huilian.iotbox.data.enums.PermissionStatusEnum;
import com.huilian.iotbox.data.enums.PermissionsTypeEnum;
import com.huilian.iotbox.data.po.Permission;
import com.huilian.iotbox.data.po.UserPermission;
import com.huilian.iotbox.data.vo.PermissionVo;
import com.huilian.iotbox.data.vo.RolePermissionTempVo;
import com.huilian.iotbox.data.vo.RoleVo;
import com.huilian.iotbox.data.vo.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author LinYinDong
 * @date 2024/10/9 下午5:38
 */
@Service
public class PermissionServiceImpl implements PermissionService {
    @Autowired
    private RoleService roleService;
    @Autowired
    private PermissionDao permissionDao;
    @Autowired
    private UserPermissionService userPermissionService;
    @Autowired
    private RolePermissionTempService rolePermissionTempService;
    @Autowired
    private RedisTemplate<String, Serializable> redisCacheTemplate;

    @Override
    public ServerResponse findPermissionList(RolePermissionTempDto rolePermissionTempDto) {
        final List<PermissionVo> pcList = getPermissionsPerLevel(0, PermissionPlatformTypeEnum.PC_WEB_PAGE.getCode(), PermissionStatusEnum.OPEN.getCode(), PermissionOpenSettingEnum.OPEN.getCode(), rolePermissionTempDto.getUserInfo(), PermissionsTypeEnum.MENU.getCode());
        final List<PermissionVo> appletList = getPermissionsPerLevel(0, PermissionPlatformTypeEnum.MERCHANT_APPLET.getCode(), PermissionStatusEnum.OPEN.getCode(), PermissionOpenSettingEnum.OPEN.getCode(), rolePermissionTempDto.getUserInfo(), PermissionsTypeEnum.MENU.getCode());
        final List<PermissionVo> deskList = getPermissionsPerLevel(0, PermissionPlatformTypeEnum.CASHIER_DESK.getCode(), PermissionStatusEnum.OPEN.getCode(), PermissionOpenSettingEnum.OPEN.getCode(), rolePermissionTempDto.getUserInfo(), PermissionsTypeEnum.MENU.getCode());
        final List<PermissionVo> handList = getPermissionsPerLevel(0, PermissionPlatformTypeEnum.HAND_SIDE_OF_THE_CASHIER.getCode(), PermissionStatusEnum.OPEN.getCode(), PermissionOpenSettingEnum.OPEN.getCode(), rolePermissionTempDto.getUserInfo(), PermissionsTypeEnum.MENU.getCode());

        for (PermissionVo permissionVo : pcList) {
            List<PermissionVo> allPermissionVoList = new ArrayList<>();
            this.mergeChild(permissionVo.getSecondStageList(), allPermissionVoList);
            if (StringUtils.isEmpty(permissionVo.getSecondStageList())) {
                permissionVo.setSecondStageList(new ArrayList<>());
            }
            permissionVo.getSecondStageList().addAll(allPermissionVoList);

            for (PermissionVo vo : permissionVo.getSecondStageList()) {
                vo.setSecondStageList(new ArrayList<>());
            }
        }
        for (PermissionVo permissionVo : appletList) {
            List<PermissionVo> allPermissionVoList = new ArrayList<>();
            this.mergeChild(permissionVo.getSecondStageList(), allPermissionVoList);
            if (StringUtils.isEmpty(permissionVo.getSecondStageList())) {
                permissionVo.setSecondStageList(new ArrayList<>());
            }
            permissionVo.getSecondStageList().addAll(allPermissionVoList);

            for (PermissionVo vo : permissionVo.getSecondStageList()) {
                vo.setSecondStageList(new ArrayList<>());
            }
        }
        for (PermissionVo permissionVo : deskList) {
            List<PermissionVo> allPermissionVoList = new ArrayList<>();
            this.mergeChild(permissionVo.getSecondStageList(), allPermissionVoList);
            if (StringUtils.isEmpty(permissionVo.getSecondStageList())) {
                permissionVo.setSecondStageList(new ArrayList<>());
            }
            permissionVo.getSecondStageList().addAll(allPermissionVoList);

            for (PermissionVo vo : permissionVo.getSecondStageList()) {
                vo.setSecondStageList(new ArrayList<>());
            }
        }
        for (PermissionVo permissionVo : handList) {
            List<PermissionVo> allPermissionVoList = new ArrayList<>();
            this.mergeChild(permissionVo.getSecondStageList(), allPermissionVoList);
            if (StringUtils.isEmpty(permissionVo.getSecondStageList())) {
                permissionVo.setSecondStageList(new ArrayList<>());
            }
            permissionVo.getSecondStageList().addAll(allPermissionVoList);

            for (PermissionVo vo : permissionVo.getSecondStageList()) {
                vo.setSecondStageList(new ArrayList<>());
            }
        }

        Map<String, Object> map = new HashMap<>();
        if (!StringUtils.isEmpty(rolePermissionTempDto.getSubUserId())) {
            // 子账号编辑权限回显
            final RoleVo roleVo = roleService.getOneRoleByIdAndUserId(rolePermissionTempDto);
            map.put("roleVo", roleVo);

            final List<UserPermission> beAuthorizedUserPermissionList = userPermissionService.findAllByUserId(rolePermissionTempDto.getSubUserId());
            Map<Integer, UserPermission> beAuthorizedUserPermissionMap = new HashMap<>();
            if (!ObjectUtils.isEmpty(beAuthorizedUserPermissionList) && beAuthorizedUserPermissionList.size() > 0) {
                beAuthorizedUserPermissionMap = beAuthorizedUserPermissionList.stream().collect(Collectors.toMap(UserPermission::getPermissionId, a -> a, (k1, k2) -> k1));
            }

            this.checkedOrNotCheckedUserPermission(pcList, beAuthorizedUserPermissionMap);
            this.checkedOrNotCheckedUserPermission(appletList, beAuthorizedUserPermissionMap);
            this.checkedOrNotCheckedUserPermission(deskList, beAuthorizedUserPermissionMap);
            this.checkedOrNotCheckedUserPermission(handList, beAuthorizedUserPermissionMap);
        } else if (!StringUtils.isEmpty(rolePermissionTempDto.getRoleId())) {
            // 角色权限模板编辑
            List<RolePermissionTempVo> rolePermissionTempByUserIdList = rolePermissionTempService.findRolePermissionTempByRoleIdList(rolePermissionTempDto.getRoleId(), rolePermissionTempDto.getUserInfo());
            final RoleVo roleVo = roleService.getOneRoleByIdAndUserId(rolePermissionTempDto);
            map.put("roleVo", roleVo);

            Map<Integer, RolePermissionTempVo> rolePermissionTempMap = new HashMap<>();
            if (!ObjectUtils.isEmpty(rolePermissionTempByUserIdList) && rolePermissionTempByUserIdList.size() > 0) {
                rolePermissionTempMap = rolePermissionTempByUserIdList.stream().collect(Collectors.toMap(RolePermissionTempVo::getPermissionId, a -> a, (k1, k2) -> k1));
            }

            this.checkedOrNotCheckedRolePermissionTemp(pcList, rolePermissionTempMap);
            this.checkedOrNotCheckedRolePermissionTemp(appletList, rolePermissionTempMap);
            this.checkedOrNotCheckedRolePermissionTemp(deskList, rolePermissionTempMap);
            this.checkedOrNotCheckedRolePermissionTemp(handList, rolePermissionTempMap);
        }
        map.put("pcList", pcList);
        map.put("appletList", appletList);
        map.put("deskList", deskList);
        map.put("handList", handList);

        return ServerResponse.createBySuccess(map);
    }

    private void checkedOrNotCheckedUserPermission(List<PermissionVo> list, Map<Integer, UserPermission> beAuthorizedUserPermissionMap) {
        for (PermissionVo permissionVo : list) {

            final UserPermission userPermission = beAuthorizedUserPermissionMap.get(permissionVo.getId());
            if (!StringUtils.isEmpty(userPermission)) {
                permissionVo.setNewField(true);
            }

            for (PermissionVo childPermission : permissionVo.getChildAPIList()) {
                final UserPermission childUserPermission = beAuthorizedUserPermissionMap.get(childPermission.getId());
                if (!StringUtils.isEmpty(childUserPermission)) {
                    childPermission.setNewField(true);
                }
            }

            this.checkedOrNotCheckedUserPermission(permissionVo.getSecondStageList(), beAuthorizedUserPermissionMap);
        }
    }

    /**
     * 递归合并二级及以上菜单、权限
     *
     * @param permissionsPerLevel
     * @param allPermissionVoList
     */
    private void mergeChild(List<PermissionVo> permissionsPerLevel, List<PermissionVo> allPermissionVoList) {
        if (StringUtils.isEmpty(permissionsPerLevel)) {
            permissionsPerLevel = new ArrayList<>();
        }
        if (StringUtils.isEmpty(allPermissionVoList)) {
            allPermissionVoList = new ArrayList<>();
        }
        for (PermissionVo permissionVo : permissionsPerLevel) {
            allPermissionVoList.addAll(permissionVo.getSecondStageList());
            mergeChild(permissionVo.getSecondStageList(), allPermissionVoList);
        }
    }

    /**
     * 递归查下级菜单、权限
     *
     * @param parenId
     * @param platformType
     * @param status
     * @param openSetting
     * @param userInfo
     * @param type
     * @return
     */
    private List<PermissionVo> getPermissionsPerLevel(
            Integer parenId,
            int platformType,
            int status,
            int openSetting,
            UserInfo userInfo,
            Integer type
    ) {
        if (StringUtils.isEmpty(parenId)) {
            return new ArrayList<>();
        }

        final String menuKey = String.format(RedisKey.PERMISSION_SECOND_STAGE_LIST, platformType, parenId);
        List<PermissionVo> permissionVoList = JSON.parseArray((String) redisCacheTemplate.opsForValue().get(menuKey), PermissionVo.class);
        if (StringUtils.isEmpty(permissionVoList)) {
            permissionVoList = permissionDao.findPermissionListByPlatformType(
                    platformType,
                    parenId,
                    status,
                    openSetting,
                    userInfo,
                    type
            );
            redisCacheTemplate.opsForValue().set(menuKey, JSON.toJSONString(permissionVoList), 24, TimeUnit.HOURS);
        }

        for (PermissionVo permissionVo : permissionVoList) {
            if (StringUtils.isEmpty(permissionVo.getType()) || !permissionVo.getType().equals(1)) {
                continue;
            }

            final String apiKey = String.format(RedisKey.PERMISSION_CHILD_API_LIST, platformType, permissionVo.getId());
            List<PermissionVo> permissionApiList = JSON.parseArray((String) redisCacheTemplate.opsForValue().get(apiKey), PermissionVo.class);
            if (StringUtils.isEmpty(permissionApiList)) {
                permissionApiList = permissionDao.findPermissionListByPlatformType(platformType, permissionVo.getId(), status, openSetting, userInfo, PermissionsTypeEnum.API.getCode());
                redisCacheTemplate.opsForValue().set(apiKey, JSON.toJSONString(permissionApiList), 24, TimeUnit.HOURS);
            }
            permissionVo.setChildAPIList(permissionApiList);

            permissionVo.setSecondStageList(this.getPermissionsPerLevel(permissionVo.getId(), platformType, status, openSetting, userInfo, type));
        }
        return permissionVoList;
    }

    /**
     * 选中某个角色时将新角色权限在列表中选中
     *
     * @param rolePermissionTempDto
     * @return
     */
    @Override
    public ServerResponse roleEchoSwitch(RolePermissionTempDto rolePermissionTempDto) {
        if (
                StringUtils.isEmpty(rolePermissionTempDto.getPcPermissionList())
                        && StringUtils.isEmpty(rolePermissionTempDto.getAppletPermissionList())
                        && StringUtils.isEmpty(rolePermissionTempDto.getDeskPermissionList())
                        && StringUtils.isEmpty(rolePermissionTempDto.getHandPermissionList())
        ) {
            return ServerResponse.createByErrorMessage("可选权限集合不能为空");
        }

        //查询是否分配了角色权限功能
        final List<RolePermissionTempVo> rolePermissionTempByUserIdList = rolePermissionTempService.findRolePermissionTempByRoleIdList(rolePermissionTempDto.getRoleId(), rolePermissionTempDto.getUserInfo());
        if (!ObjectUtils.isEmpty(rolePermissionTempByUserIdList)) {
            final Map<Integer, RolePermissionTempVo> existRolePermissionTempMap = rolePermissionTempByUserIdList.stream().collect(Collectors.toMap(RolePermissionTempVo::getPermissionId, a -> a, (k1, k2) -> k1));

            List<PermissionVo> pcPermissionList = rolePermissionTempDto.getPcPermissionList();
            this.checkedOrNotCheckedRolePermissionTemp(pcPermissionList, existRolePermissionTempMap);
            rolePermissionTempDto.setPcPermissionList(pcPermissionList);

            List<PermissionVo> appletPermissionList = rolePermissionTempDto.getAppletPermissionList();
            this.checkedOrNotCheckedRolePermissionTemp(appletPermissionList, existRolePermissionTempMap);
            rolePermissionTempDto.setAppletPermissionList(appletPermissionList);

            List<PermissionVo> deskPermissionList = rolePermissionTempDto.getDeskPermissionList();
            this.checkedOrNotCheckedRolePermissionTemp(deskPermissionList, existRolePermissionTempMap);
            rolePermissionTempDto.setDeskPermissionList(deskPermissionList);

            List<PermissionVo> handPermissionList = rolePermissionTempDto.getHandPermissionList();
            this.checkedOrNotCheckedRolePermissionTemp(handPermissionList, existRolePermissionTempMap);
            rolePermissionTempDto.setHandPermissionList(handPermissionList);
        }
        RolePermissionTempDto dto = new RolePermissionTempDto();
        dto.setPcPermissionList(rolePermissionTempDto.getPcPermissionList());
        dto.setAppletPermissionList(rolePermissionTempDto.getAppletPermissionList());
        dto.setDeskPermissionList(rolePermissionTempDto.getDeskPermissionList());
        dto.setHandPermissionList(rolePermissionTempDto.getHandPermissionList());
        return ServerResponse.createBySuccess(dto);
    }


    private void checkedOrNotCheckedRolePermissionTemp(List<PermissionVo> list, Map<Integer, RolePermissionTempVo> existRolePermissionTempMap) {
        for (PermissionVo permissionVo : list) {

            final RolePermissionTempVo rolePermissionTempVo = existRolePermissionTempMap.get(permissionVo.getId());
            if (!StringUtils.isEmpty(rolePermissionTempVo)) {
                permissionVo.setNewField(true);
            }

            for (PermissionVo childPermission : permissionVo.getChildAPIList()) {
                final RolePermissionTempVo childRolePermissionTempVo = existRolePermissionTempMap.get(childPermission.getId());
                if (!StringUtils.isEmpty(childRolePermissionTempVo)) {
                    childPermission.setNewField(true);
                }
            }

            this.checkedOrNotCheckedRolePermissionTemp(permissionVo.getSecondStageList(), existRolePermissionTempMap);
        }
    }


    @Override
    public List<Permission> findAllPermissionByIdListAndOther(List<Integer> inPermissionIdList, Permission permissionCondition) {
        return permissionDao.permissionCondition(inPermissionIdList, permissionCondition);
    }
}
